----------------------所有类的基类对象----------------------
--[[
	类名以 cls 开头
	所有类对象的函数统一以大写字母为首,驼峰标记法
	模块函数例如 module_xxx 等函数除外

	!!注意: 在数据保存方面,
		1. 注册为 RegSaveVar 的变量必须显式调用 Setxxx 才会被标记为修改状态!
		2. 只有存在修改状态的变量才会被间隔时间保存到数据库进程!
		3. 类对象必须指定 DBObj 来保存 Setxxx 的修改
]]

local SAVE_INTERVAL = 60 * 5 --有修改的数据间隔 n 分钟发送到db进程

function module_init(self)
    -- 初始化实例属性存储结构
    self.clsObj:__InitInstAttr()
    -- 数据保存必须存在的对象属性
    self.clsObj:RegSaveVar("_Type")       -- 从属类名
    self.clsObj:RegSaveVar("_Save_Count") -- 保存计数（用于版本控制或冲突检测）
    self.clsObj:RegSaveVar("CreatedTime") -- 创建时间
    self.clsObj:RegTmpVar("DBObj")        -- 临时属性：数据库对象（不保存到数据库）
end

-- 空更新函数（热更预留）
function module_update(self) end

clsObj             = {}       -- 基类对象
clsObj._class_name = "clsObj" -- 类名标识

-- 特殊索引定义（使用负数避免冲突）
local _tmp_idx     = -1 -- 临时属性存储索引
local _save_idx    = -2 -- 持久化属性存储索引
local _change_idx  = -3 -- 修改标记存储索引

--创建子类对象
function clsObj:Child(clsName)
    assert(type(clsName) == "string")
    local childCls = {}
    local mt = { __index = self } -- 设置元表继承自当前类
    setmetatable(childCls, mt)
    childCls:__InitInstAttr()     -- 初始化子类属性
    childCls:SetClsName(clsName)  -- 设置子类名
    return childCls
end

--创建类的一个实例
function clsObj:New(...)
    local obj = {}
    -- 创建类元表（所有实例共享）
    if not self.__mt then self.__mt = { __index = self } end
    setmetatable(obj, self.__mt)

    -- 初始化对象属性
    obj:__InitInstAttr()
    -- 设置核心属性
    obj:Set_Type(self:GetClsName()) -- 记录对象类型
    obj:Set_Save_Count(0)           -- 初始化保存计数器
    obj:SetCreatedTime(os.time())   -- 记录创建时间

    -- 调用对象创建回调
    if obj.OnCreate then
        obj:OnCreate(...)
    end

    return obj
end

--实例对象属性保存
function clsObj:__InitInstAttr()
    -- 确保属性存储结构未初始化
    assert(not rawget(self, _tmp_idx) and not rawget(self, _save_idx))
    -- 初始化三个核心存储表
    self[_tmp_idx]    = {} -- 临时属性
    self[_save_idx]   = {} -- 持久化属性
    self[_change_idx] = {} -- 修改标记
end

-- 对象创建回调（用于反序列化，即将数据库存储的数据赋值给类对象）
--1. 如果 oci.xx 是单个嵌套类实例可以根据 oci.xx 重现类实例对象;
--2. 如果 oci.xx 是多个嵌套类实例(列表),则只能在各自的类的OnCreate函数,根据列表每个类对象实例
function clsObj:OnCreate(oci)
    local vtype
    for k, v in pairs(oci or {}) do
        local fname = "Set" .. k
        if self[fname] then -- 检查是否存在setter方法
            vtype = type(v)
            -- 处理嵌套类对象
            if vtype == "table" and v._Type and v._Save_Count then
                local cls = ALL_CLASS[v._Type] -- 从全局注册表获取类
                if cls then
                    -- 递归创建嵌套对象
                    local obj = cls:New(v)
                    self[fname](self, obj) -- 调用setter设置对象
                end
            else
                self[fname](self, v) -- 设置普通值
            end
        end
    end
end

-- 对象销毁回调
function clsObj:OnDestroy() end

-- 属性访问器生成
function clsObj:RegAttrFunc(idx, varName)
    --get不能检查 CheckSaveVarChange ,不然会容易出现死循环
    local funcName = "Get" .. varName
    self[funcName] = function(obj)
        return obj[idx][varName]
    end

    funcName = "Set" .. varName
    self[funcName] = function(obj, value) --反序列化为类对象时不需要标记修改
        -- 设置属性值
        obj[idx][varName] = value

        -- 如果是持久化属性
        if idx == _save_idx then
            -- 检查是否关联了数据库对象（类对象没有指定 DBObj 就不用使用 Setxxx 定时保存）
            if not obj:GetDBObj() then return end

            -- 标记属性已修改
            obj[_change_idx][varName] = true

            -- 延迟保存机制
            local now = os.time()
            local time = obj[_tmp_idx]["__dct"] -- 下次保存时间
            if not time then
                -- 首次修改：设置5分钟后保存
                obj[_tmp_idx]["__dct"] = now + SAVE_INTERVAL
            elseif now >= time then
                -- 到达保存时间：立即保存
                obj:CheckSaveVarChange(true)
                obj[_tmp_idx]["__dct"] = now + SAVE_INTERVAL
            end
        end
    end
end

-----------------------------保存控制相关函数-----------------------------
-- 强制重置保存时间（用于紧急保存）
function clsObj:ResetCheckSaveVarTime()
    if self[_tmp_idx]["__dct"] then
        self[_tmp_idx]["__dct"] = os.time() + 1
    end
end

-- 检查并保存修改
function clsObj:CheckSaveVarChange(is_save_whole)
    -- 全量保存
    if is_save_whole then
        local dbObj = self:GetDBObj()
        dbObj:SaveWhole(self)
    else
        -- 增量保存
        local piece = {}
        for varName, _ in pairs(self[_change_idx]) do
            if self[_save_idx][varName] then
                piece[#piece + 1] = varName
            end
        end
        if next(piece) then
            local dbObj = self:GetDBObj()
            dbObj:SavePiece(self, piece)
            self[_change_idx] = {} -- 清空修改标记
        end
    end
end

-- 清空所有修改标记
function clsObj:ResetSaveVarChangeWhole()
    self[_change_idx] = {}
end

-- 清除指定属性的修改标记
function clsObj:ResetSaveVarChangePiece(piece)
    for _, varName in ipairs(piece) do
        self[_change_idx][varName] = nil
    end
end

-----------------------------属性注册方法-----------------------------
-- 注册持久化属性
function clsObj:RegSaveVar(varName)
    self:RegAttrFunc(_save_idx, varName)
end

-- 注册临时属性
function clsObj:RegTmpVar(varName)
    self:RegAttrFunc(_tmp_idx, varName)
end

-- 批量注册临时属性
function clsObj:RegTmpAttrFromCfg(attrs)
    for _, attrName in pairs(attrs) do
        self:RegTmpVar(attrName)
    end
end

-- 批量注册持久化属性
function clsObj:RegSaveAttrFromCfg(attrs)
    for _, attrName in pairs(attrs) do
        self:RegSaveVar(attrName)
    end
end

-----------------------------数据序列化-----------------------------
-- 获取保存数据（处理嵌套对象）
function clsObj:GetSaveData(piece, fetchList)
    local data = self[_save_idx]
    data._Save_Count = data._Save_Count + 1 -- 更新保存计数

    local retData
    if piece then -- 部分保存
        local pieceData = {}
        for _, attrName in ipairs(piece) do
            pieceData[attrName] = data[attrName]
        end
        retData = _GetRealSaveData(pieceData, fetchList)
        retData._Save_Count = data._Save_Count
    else
        -- 全量保存
        retData = _GetRealSaveData(data, fetchList)
    end

    return retData
end

-- 递归处理嵌套对象
function _GetRealSaveData(data, fetchList)
    local retData = {}

    for k, v in pairs(data) do
        if type(v) == "table" then
            --不允许相同的table被成员变量类实例下记录多次,防止出现死循环
            if fetchList[v] then assert(false) end
            fetchList[v] = true

            -- 处理类实例对象
            if type(v.GetClsName) == "function" and type(v.GetSaveData) == "function" then
                retData[k] = v:GetSaveData(nil, fetchList)
            else
                retData[k] = _GetRealSaveData(v, fetchList)
            end
        else
            retData[k] = v -- 基本类型直接复制
        end
    end
    return retData
end

-- 设置类名
function clsObj:SetClsName(clsName)
    assert(type(clsName) == "string")
    self._class_name = clsName
end

-- 获取类名
function clsObj:GetClsName()
    return self._class_name
end

-- 默认属性初始化
function clsObj:InitDefaultAttr(defaultAttr)
    local fname, func, value
    for attrName, v in pairs(defaultAttr) do
        fname = "Get" .. attrName
        func = self[fname]
        if func then
            value = func(self)
            -- 仅当属性未设置时初始化默认值
            if not value then
                fname = "Set" .. attrName
                if type(v) == "table" then
                    local nv = table.deepCopy(v) -- 深拷贝表类型默认值
                    self[fname](self, nv)
                else
                    self[fname](self, v)
                end
            end
        end
    end
end

-- 获取调试信息
function clsObj:ToDebugInfo()
    return self._class_name
end

-- 强制保存对象
function clsObj:Save()
    local dbObj = self:GetDBObj()
    if dbObj then
        dbObj:SaveWhole(self)
    end
end
